package panda.buffer;

import java.util.HashMap;

import panda.file.Block;
import panda.server.Panda;

public class BasicBufferManager {
	private Buffer[] bufferPool;

	private int hand;

	private int bufferNumber;

	private int availableNumber;

	private int[] reference;

	private final int N = 2;

	private HashMap<Block, Integer> existingBuffer = new HashMap<Block, Integer>();

	public BasicBufferManager(int bufferNumber) {
		hand = 0;
		this.bufferNumber = bufferNumber;
		bufferPool = new Buffer[bufferNumber];
		reference = new int[bufferNumber];
		availableNumber = bufferNumber;
		for (int i = 0; i < bufferNumber; i++) {
			bufferPool[i] = new Buffer();
			reference[i] = 0;
		}
	}

	synchronized Buffer pin(Block block) {
		int buffer = -1;
		Integer getBuffer=existingBuffer.get(block);
		if (getBuffer!=null){
			buffer=getBuffer;
		}else{
			buffer = clock();
			if (buffer == -1)
				return null;
			existingBuffer.remove(bufferPool[buffer].getBlock());
			bufferPool[buffer].pageIn(block);
			existingBuffer.put(block, buffer);
		}
		if (!bufferPool[buffer].ispinned())
			availableNumber--;
		bufferPool[buffer].pin();
		return bufferPool[buffer];
	}

	synchronized Buffer pinNew(String fileName, PageFormatter formatter) {
		int buffer = clock();
		if (buffer == -1)
			return null;
		existingBuffer.remove(bufferPool[buffer].getBlock());
		bufferPool[buffer].newPageIn(fileName, formatter);
		availableNumber--;
		bufferPool[buffer].pin();
		existingBuffer.put(bufferPool[buffer].getBlock(), buffer);
		return bufferPool[buffer];
	}

	synchronized void unPin(Buffer buffer) {
		buffer.unpin();
		if (!buffer.ispinned()) {
			availableNumber++;
		}
	}

	int available() {
		return availableNumber;
	}

	synchronized void allPageOut(int transactionID) {
		for (int i = 0; i < bufferNumber; i++) {
			if (bufferPool[i].isModifiedBy(transactionID)) {
				bufferPool[i].pageOut();
				existingBuffer.remove(bufferPool[i].getBlock());
			}
		}
	}
	
	synchronized void clear(String fileName){
		try {
			int size=Panda.getFileManager().size(fileName);
			for (int i=0;i<size;i++){
				Block block=new Block(fileName,i);
				if (existingBuffer.containsKey(block)){
					bufferPool[existingBuffer.get(block)]=null;
					existingBuffer.remove(block);
				}
			}
		} catch (Exception e) {
		}
		
	}

	private int clock() {
		boolean found = false;
		int start = hand;
		while (true) {
			hand++;
			if (hand == bufferNumber) {
				hand = 1;
			}
			if (!bufferPool[hand].ispinned()) {
				found = true;
				if (reference[hand] == 0) {
					reference[hand] = N - 1;
					return hand;
				} else {
					reference[hand]--;
				}
			}
			if ((hand == start) && (!found)) {
				return -1;
			}
		}
	}
}
